package cn.cvs.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import cn.cvs.config.shiro.MyShiroRealm;
import cn.cvs.pojo.SysRight;
import cn.cvs.service.RoleShiroService;
import cn.cvs.service.SysRightService;
import org.apache.ibatis.annotations.Result;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Configuration
public class ShiroConfig {

    private Logger logger= LogManager.getLogger();


    //注入redis参数,从yml中获取
    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.port}")
    private int port;

    @Value("${spring.redis.timeout}")
    private int timeout;

    @Value("${spring.redis.password}")
    private String password;

    @Resource
    RoleShiroService roleShiroService;

    @Resource
    SysRightService rightService;

    /**
     * 开启Shiro注解 如 @RequireRoles,@RequirePermissions
     * 需借助SpringAop扫描使用shiro注解的类,在必要是进行安全逻辑验证
     * 配置以下2个bean
     *  MyShiroRealm 中添加   info.addStringPermission("useredit");
     * UserController_shiro 中对应方法添加注解   @RequiresPermissions(value = "useredit")
     * 若无权限,跳转至403界面
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator creator =new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }

    /**
     * 开启方法注解权限控制 aop注解支持
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor advisor =new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;

    }

    @Bean
    public MyShiroRealm myShiroRealm(){
        MyShiroRealm shiroRealm = new MyShiroRealm();

        //设置启用缓存,并设置缓存时间
        shiroRealm.setCachingEnabled(true);
        shiroRealm.setAuthorizationCachingEnabled(true);
        shiroRealm.setAuthorizationCacheName("authorizationCache");

        return shiroRealm;
    }

    @Bean
    public DefaultSecurityManager securityManager(){
        DefaultWebSecurityManager securityManager =new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm());

        //注入缓存管理器
        securityManager.setCacheManager(cacheManager());
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
        //shiro过滤器  权限验证
        ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager());

        //权限认证
        shiroFilterFactoryBean.setLoginUrl("/sindex");
        shiroFilterFactoryBean.setSuccessUrl("/smain");
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");
        //有序集合
        Map<String,String> filterChainDefinitionMap = new LinkedHashMap<>();
        //过滤器链
        //添加配置: 静态资源URL 可以匿名访问(anon)
        filterChainDefinitionMap.put("/css/**","anon");
        filterChainDefinitionMap.put("/fonts/**","anon");
        filterChainDefinitionMap.put("/images/**","anon");
        filterChainDefinitionMap.put("/js/**","anon");
        filterChainDefinitionMap.put("/localcss/**","anon");
        filterChainDefinitionMap.put("/localjs/**","anon");
        //登录注销请求可以匿名访问
        filterChainDefinitionMap.put("/login","anon");
        filterChainDefinitionMap.put("/logout","anon");
        filterChainDefinitionMap.put("/sindex","anon");
        filterChainDefinitionMap.put("/slogin","anon");


        //静态授权:需要特定权限才能访问的资源
        /*
        filterChainDefinitionMap.put("/suser/list","perms[用户列表]");
        filterChainDefinitionMap.put("/suser/add","perms[用户添加]");
        filterChainDefinitionMap.put("/suser/edit","perms[用户编辑]");
        filterChainDefinitionMap.put("/suser/del","perms[用户删除]");
        */

        //配置认证访问 其他资源url必须通过认证才能访问
        //动态授权
        //动态获取权限列表
        List<SysRight> allSysRight = rightService.getAllSysRight();
        allSysRight.forEach(sysRightVO -> {
            if (null != sysRightVO){
                if (null!=sysRightVO.getRightUrl() && !"".equals(sysRightVO.getRightUrl().trim())){
                    filterChainDefinitionMap.put(sysRightVO.getRightUrl(),"perms["+sysRightVO.getRightCode()+"]");
                }
            }
        });

        filterChainDefinitionMap.put("/druid/*","authc");
        //必须放在过滤器链最后面
        filterChainDefinitionMap.put("/**","authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);


        return shiroFilterFactoryBean;
    }


    @Bean//thymeleaf使用shiro标签
    public ShiroDialect shiroDialect(){
        return  new ShiroDialect();
    }


    /**
     * 初始化RedisManager
     */
    @Bean
    public RedisManager redisManager(){
        RedisManager redisManager =new RedisManager();
        redisManager.setHost(host);
        redisManager.setPort(port);
        redisManager.setPassword(password);
        redisManager.setTimeout(timeout);
        return redisManager;
    }

    /**
     * 初始化Redis缓存对象
     */
    public RedisCacheManager cacheManager(){
        RedisCacheManager cacheManager =new RedisCacheManager();
        cacheManager.setRedisManager(redisManager());
        //缓存名称
        cacheManager.setPrincipalIdFieldName("usrName");
        //设置失效时间
        cacheManager.setExpire(1800);
        return cacheManager;
    }

    /**
     * 会话操作
     */
    public RedisSessionDAO redisSessionDAO(){
        RedisSessionDAO redisSessionDAO=new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }

    /**
     * 会话管理
     */
    public DefaultWebSessionManager sessionManager(){
        DefaultWebSessionManager sessionManager =new DefaultWebSessionManager();
        sessionManager.setSessionDAO(redisSessionDAO());
        return sessionManager;
    }
}

